package com.example.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.PageResult;
import com.example.common.enums.ErrorCodeEnum;
import com.example.common.enums.RoleEnum;
import com.example.exception.CustomException;
import com.example.mapper.CommentMapper;
import com.example.pojo.dto.CommentQueryDto;
import com.example.pojo.entity.Account;
import com.example.pojo.entity.Comment;
import com.example.pojo.entity.Post;
import com.example.pojo.entity.User;
import com.example.pojo.vo.CommentQueryVo;
import com.example.utils.AccountUtils;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

/**
 * 评论 service 层实现类
 */
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Resource
    private UserService userService;

    @Resource
    private PostService postService;

    /**
     * 普通用户发布评论
     *
     * @param comment 评论
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendComment(Comment comment) {
        // 1.校验角色是否是普通用户
        User dbUser = this.checkUser();

        // 2.校验参数
        if (comment.getPostId() == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        if (StrUtil.isBlank(comment.getContent())) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 3.构建参数
        // 3.1 评论人id
        comment.setUserId(dbUser.getId());
        // 3.2 父评论为空
        comment.setParentId(null);
        // 3.2 发布评论时间
        comment.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 4.存入数据库
        this.save(comment);

        // 5.修改其根id为自己id
        this.lambdaUpdate()
                .eq(Comment::getId, comment.getId())
                .set(Comment::getRootId, comment.getId())
                .update();
    }

    /**
     * 普通用户回复评论
     *
     * @param comment 回复
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void replyComment(Comment comment) {
        // 1.校验角色是否是普通用户
        User dbUser = this.checkUser();

        // 2.校验参数
        if (comment.getPostId() == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        if (StrUtil.isBlank(comment.getContent())) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        if (comment.getParentId() == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        if (comment.getRootId() == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 3.构建参数
        // 3.1 回复人id
        comment.setUserId(dbUser.getId());
        // 3.2 发布评论时间
        comment.setCreateTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 4.存入数据库
        this.save(comment);
    }

    /**
     * 分页査询自己的评论
     *
     * @param dto 条件
     * @return 分页结果
     */
    @Override
    public PageResult<CommentQueryVo> pageQueryPersonComment(CommentQueryDto dto) {
        // 1.校验参数
        if (dto == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        if (dto.getPageNum() == null || dto.getPageNum() < 1) {
            throw new CustomException(ErrorCodeEnum.PAGE_QUERY_NUM);
        }
        if (dto.getPageSize() == null || dto.getPageSize() < 1 || dto.getPageSize() > 100) {
            throw new CustomException(ErrorCodeEnum.PAGE_QUERY_SIZE);
        }

        // 2.校验角色是否是普通用户
        User dbUser = this.checkUser();

        // 3.创建 MybatisPlus 分页对象
        IPage<CommentQueryVo> pageObject = new Page<>(dto.getPageNum(), dto.getPageSize());

        // 4.分页查询自己的评论
        dto.setUserId(dbUser.getId());
        pageObject = this.getBaseMapper().pageQuery(pageObject, dto);

        // 5.构建分页结果并返回
        return new PageResult<>(
                pageObject.getTotal(),
                pageObject.getRecords()
        );
    }


    /**
     * 查询一个帖子的评论
     *
     * @param postId 帖子id
     * @return 评论树
     */
    @Override
    public List<CommentQueryVo> queryCommentTree(Integer postId) {
        // 1.校验参数
        if (postId == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.校验角色是否是普通用户
        this.checkUser();

        // 3.查询一个帖子的所有评论
        List<CommentQueryVo> commentList = this.getBaseMapper().queryCommentByPostId(postId);

        // 4.parentId为空的评论就是根节点评论，先过淲出根节点评论
        List<CommentQueryVo> rootCommentList = commentList.stream()
                .filter(comment -> comment.getParentId() == null)
                .toList();

        // 5.构建评论树
        for (CommentQueryVo rootComment : rootCommentList) {
            Integer rootId = rootComment.getRootId();
            List<CommentQueryVo> childCommentList = commentList.stream()
                    .filter(comment -> comment.getParentId() != null && comment.getRootId().equals(rootId))
                    .toList();
            rootComment.setChildComment(childCommentList);
        }

        // 6.返回评论树
        return rootCommentList;
    }

    /**
     * 查询一个帖子的评论数量
     *
     * @param postId 帖子id
     * @return 帖子的评论数量
     */
    @Override
    public long queryPostTotalComment(Integer postId) {
        // 1.校验参数
        if (postId == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }
        // 2.根据帖子id查询帖子的评论数量
        return this.lambdaQuery()
                .eq(Comment::getPostId, postId)
                .count();
    }

    /**
     * 删除评论及其子评论
     *
     * @param id 评论id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCommentAndChildComment(Integer id) {
        // 1.校验参数
        if (id == null) {
            throw new CustomException(ErrorCodeEnum.PARAM_LOST_ERROR);
        }

        // 2.校验角色是否是普通用户
        User dbUser = this.checkUser();
        int curUserId = dbUser.getId();

        // 3.获取评论的发布人 id
        Comment dbComment = this.lambdaQuery()
                .eq(Comment::getId, id)
                .one();
        if (dbComment == null) {
            throw new CustomException(ErrorCodeEnum.COMMENT_NOT_EXITS);
        }
        int commentUserId = dbComment.getUserId();

        // 4.获取帖子的发布人 id
        Post dbPost = this.postService.lambdaQuery()
                .eq(Post::getId, dbComment.getPostId())
                .one();
        if (dbPost == null) {
            throw new CustomException(ErrorCodeEnum.POST_NOT_EXITS);
        }
        int postUserId = dbPost.getUserId();

        // 5.校验评论的发布人是否当前用户 或 评论的帖子的发布人是当前用户
        if (curUserId != commentUserId && curUserId != postUserId) {
            throw new CustomException(ErrorCodeEnum.ONLY_ROLE_DELETE_COMMENT);
        }

        // 6.删除评论及其子评论
        this.deleteAllChildren(id);
    }

    @Transactional(rollbackFor = Exception.class)
    public void deleteAllChildren(Integer parentId) {
        this.removeById(parentId);
        List<Comment> commentList = this.lambdaQuery()
                .eq(Comment::getParentId, parentId)
                .list();
        if (CollectionUtil.isEmpty(commentList)) {
            return;
        }
        for (Comment comment : commentList) {
            deleteAllChildren(comment.getId());
        }
    }

    /**
     * 校验角色是否是普通用户
     *
     * @return 普通用户
     */
    private User checkUser() {
        Account currentLoginAccount = AccountUtils.getCurrentLoginAccount();
        if (currentLoginAccount == null) {
            throw new CustomException(ErrorCodeEnum.GET_CUR_USER_ERROR);
        }
        if (!RoleEnum.USER.name().equals(currentLoginAccount.getRole())) {
            throw new CustomException(ErrorCodeEnum.ONLY_USER_CART);
        }
        User dbUser = this.userService.lambdaQuery()
                .eq(User::getUsername, currentLoginAccount.getUsername())
                .one();
        if (dbUser == null) {
            throw new CustomException(ErrorCodeEnum.GET_CUR_USER_ERROR);
        }
        return dbUser;
    }
}
